package com.ticket.sass.admin.business.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.ticket.sass.admin.business.CouponBusiness;
import com.ticket.sass.admin.dto.input.WeekTimeInput;
import com.ticket.sass.admin.dto.input.coupons.CouponAddInput;
import com.ticket.sass.admin.dto.input.coupons.CouponListInput;
import com.ticket.sass.admin.dto.input.coupons.CouponUpdInput;
import com.ticket.sass.admin.dto.output.WeekTimeOutput;
import com.ticket.sass.admin.dto.output.coupons.CouponListOutput;
import com.ticket.sass.admin.dto.output.coupons.CouponOutput;
import com.ticket.sass.admin.model.LabModel;
import com.ticket.sass.admin.model.PageModel;
import com.ticket.sass.admin.service.impl.*;
import com.ticket.sass.admin.util.CinemaIdUtil;
import com.ticket.sass.admin.util.EscapeUtil;
import com.ticket.sass.admin.util.ModelUtil;
import com.ticket.sass.common.entity.tenant.*;
import com.ticket.sass.common.entity.tenant.enums.CouponActivateType;
import com.ticket.sass.common.entity.tenant.enums.CouponAvailablePeriod;
import com.ticket.sass.common.entity.tenant.enums.CouponScene;
import com.ticket.sass.common.entity.tenant.enums.CouponType;
import com.ticket.sass.common.exception.enums.ErrorCode;
import com.ticket.sass.common.exception.exception.BadRequestException;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author ywb
 * @date 2021-11-15 15:43
 */

@Service
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class CouponBusinessImpl implements CouponBusiness {
    
    final ModelUtil modelUtil;
    final CouponServiceImpl service;
    final FilmServiceImpl filmService;
    final HallServiceImpl hallService;
    final CommodityServiceImpl commodityService;
    final CouponWeekServiceImpl couponWeekService;
    final CommoditySkuServiceImpl commoditySkuService;
    final CouponFilmMapServiceImpl couponFilmMapService;
    final CouponHallMapServiceImpl couponHallMapService;
    final CouponCinemaMapServiceImpl couponCinemaMapService;
    final CouponCommodityMapServiceImpl couponCommodityMapService;

    
    @Override
    public PageModel<CouponListOutput> list(CouponListInput input) {
        IPage<CouponEntity> page = service.iPage(input);
        
        List<Long> couponIds = page.getRecords().stream().map(CouponEntity::getId).collect(Collectors.toList());
        
        Map<Long, List<CouponWeekEntity>> couponWeeksMap = couponWeekService.listByCouponIds(couponIds);
        
        List<CouponListOutput> outputs = page.getRecords().stream()
            .map(coupon -> {
                CouponListOutput output = CouponListOutput.toOutput(coupon);
                List<CouponWeekEntity> couponWeeks = couponWeeksMap.getOrDefault(coupon.getId(), new ArrayList<>());
                output.setWeekTimes(
                    couponWeeks.stream().map(WeekTimeOutput::new).collect(Collectors.toList())
                );
                return output;
            })
            .collect(Collectors.toList());
        
        return new PageModel<>(page.getTotal(), outputs);
    }
    
    @Override
    public CouponOutput find(Long id) {
        validateId(id);
        CouponEntity coupon = service.getById(id);
        CouponOutput output = CouponOutput.toOutput(coupon);
        
        // 设置 WeekTimes
        List<CouponWeekEntity> couponWeeks = couponWeekService.listByCouponId(id);
        output.setWeekTimes(couponWeeks.stream()
            .map(WeekTimeOutput::new)
            .collect(Collectors.toList()));
        
        // 设置 Commodities
        List<LabModel> commodities = commodityService.queryCommoditiesByCouponId(id)
            .stream()
            .map(commodity -> new LabModel(commodity.getId(), commodity.getName()))
            .collect(Collectors.toList());
        output.setCommodities(commodities);
        
        // 设置 Films
        List<LabModel> films = filmService.queryFilmsByCouponId(id)
            .stream()
            .map(film -> new LabModel(film.getId(), film.getName()))
            .collect(Collectors.toList());
        output.setFilms(films);
        
        // 设置 Halls
        List<LabModel> halls = hallService.queryHallsByCouponId(id)
            .stream()
            .map(hall -> new LabModel(hall.getId(), hall.getName()))
            .collect(Collectors.toList());
        output.setHalls(halls);
        
        
        return output;
    }
    

    @Override
    public void add(CouponAddInput input) {
        CouponType couponType = CouponType.Companion.valueOf(input.getType());
        CouponScene couponScene = CouponScene.Companion.valueOf(input.getScene());
        validateCommodityCoupon(input.getCommodityIds(), couponType, couponScene);
        
        Long cinemaId = CinemaIdUtil.getCinemaIdFromRequest();
        CouponEntity coupons = modelUtil.mapToMap(input, CouponEntity.class);
        coupons.setType(couponType);
        coupons.setScene(couponScene);
        coupons.setActivateType(CouponActivateType.Companion.valueOf(input.getActivateType()));
        coupons.setAvailablePeriod(CouponAvailablePeriod.Companion.valueOf(input.getAvailablePeriod()));
        coupons.setAllowCard(!input.getMemberCardDisabled());
        coupons.setCinemaId(cinemaId);
        service.save(coupons);
        
        
        
        // 卖品关联
        List<Long> commoditiesIds = input.getCommodityIds();
        if (CollectionUtil.isEmpty(commoditiesIds)) {
            commoditiesIds = List.of(0L);
        }
        List<CouponCommodityMapEntity> commodityMapEntities = commoditiesIds.stream()
            .map(id -> new CouponCommodityMapEntity(id, coupons.getId()))
            .collect(Collectors.toList());
        couponCommodityMapService.saveBatch(commodityMapEntities);
        
        // 保存时间
        if (1 == input.getAvailablePeriod()) {
            List<CouponWeekEntity> priceSchemeWeekEntities = input.getWeekTimes().stream()
                .map(weekTimeInput -> {
                    CouponWeekEntity weekEntity = new CouponWeekEntity();
                    weekEntity.setWeek(weekTimeInput.getWeek());
                    weekEntity.setCinemaId(cinemaId);
                    weekEntity.setCouponId(coupons.getId());
                    weekEntity.setTimes(WeekTimeInput.getString(weekTimeInput.getTimes(), true));
                    return weekEntity;
                })
                .collect(Collectors.toList());
            couponWeekService.saveBatch(priceSchemeWeekEntities);
        }
        
        // 影院关联
        couponCinemaMapService.save(new CouponCinemaMapEntity(cinemaId, coupons.getId()));
        
        // 影片关联
        List<Long> filmIds = input.getFilmIds();
        
        if (CollectionUtil.isEmpty(filmIds)) {
            filmIds = List.of(0L);
        }
        List<CouponFilmMapEntity> filmMapEntities = filmIds.stream()
            .map(id -> new CouponFilmMapEntity(id, coupons.getId()))
            .collect(Collectors.toList());
        couponFilmMapService.saveBatch(filmMapEntities);
        
        
        // 影厅关联
        List<Long> hallIds = input.getHallIds();
        
        if (CollectionUtil.isEmpty(hallIds)) {
            hallIds = List.of(0L);
        }

        couponHallMapService.saveRelations(coupons.getId(), hallIds, "coupon_id", "hall_id");
        
    }
    
    @Override
    public void upd(CouponUpdInput input) {
        validateId(input.getId());
//        CouponEntity coupon = service.getById(input.getId());
        
        // 已被领取
//        if (coupon.getReceiveCount() > 0) {
//            throw new BadRequestException(ErrorCode.BUSINESS_ERROR, EscapeUtil.errorMessage("id", "已有用户使用，不可修改"));
//        }
//        CouponType couponType = CouponType.Companion.valueOf(input.getType());
//        CouponScene couponScene = CouponScene.Companion.valueOf(input.getScene());
//        validateCommodityCoupon(input.getCommoditiesIds(), couponType, couponScene);
        
        CouponEntity coupons = modelUtil.mapToMap(input, CouponEntity.class);
//        coupons.setType(couponType);
//        coupons.setScene(couponScene);
//        coupons.setActivateType(CouponActivateType.Companion.valueOf(input.getActivateType()));
        coupons.setAvailablePeriod(CouponAvailablePeriod.Companion.valueOf(input.getAvailablePeriod()));
        coupons.setAllowCard(!input.getMemberCardDisabled());
        service.updateById(coupons);
        
        // 保存时间
        if (1 == input.getAvailablePeriod()) {
            couponWeekService.remove(new QueryWrapper<CouponWeekEntity>().eq("coupon_id", coupons.getId()));
            
            List<CouponWeekEntity> priceSchemeWeekEntities = input.getWeekTimes().stream()
                .map(weekTimeInput -> {
                    CouponWeekEntity weekEntity = new CouponWeekEntity();
                    weekEntity.setWeek(weekTimeInput.getWeek());
                    weekEntity.setCouponId(coupons.getId());
                    weekEntity.setTimes(WeekTimeInput.getString(weekTimeInput.getTimes(), true));
                    return weekEntity;
                })
                .collect(Collectors.toList());
            couponWeekService.saveBatch(priceSchemeWeekEntities);
        }
        
//        couponCommodityMapService.remove(new QueryWrapper<CouponCommodityMapEntity>().eq("coupon_id", coupons.getId()));
//        // 卖品关联
//        List<Long> commoditiesIds = input.getCommoditiesIds();
//        if (CollectionUtil.isEmpty(commoditiesIds)) {
//            commoditiesIds = List.of(0L);
//        }
//        List<CouponCommodityMapEntity> commodityMapEntities = commoditiesIds.stream()
//            .map(id -> new CouponCommodityMapEntity(id, coupons.getId()))
//            .collect(Collectors.toList());
//        couponCommodityMapService.saveBatch(commodityMapEntities);
//
//
//
//        couponFilmMapService.remove(new QueryWrapper<CouponFilmMapEntity>().eq("coupon_id", coupons.getId()));
//        // 影片关联
//        List<Long> filmIds = input.getFilmIds();
//
//        if (couponScene == CouponScene.TICKET && couponType == CouponType.DEDUCTION) {
//            if (CollUtil.isEmpty(filmIds) || filmIds.size() != 1) {
//                throw new BadRequestException(ErrorCode.BUSINESS_ERROR, EscapeUtil.errorMessage("filmIds", "当前情景下，影片只允许选一个"));
//            }
//        }
//        if (CollectionUtil.isEmpty(filmIds)) {
//            filmIds = List.of(0L);
//        }
//        List<CouponFilmMapEntity> filmMapEntities = filmIds.stream()
//            .map(id -> new CouponFilmMapEntity(id, coupons.getId()))
//            .collect(Collectors.toList());
//        couponFilmMapService.saveBatch(filmMapEntities);
        
        
        // 影厅关联
        List<Long> hallIds = input.getHallIds();
        
        if (CollectionUtil.isEmpty(hallIds)) {
            hallIds = List.of(0L);
        }
        
        couponHallMapService.updateRelations(coupons.getId(), hallIds, "coupon_id", "hall_id");
    }
    
    // 校验 卖品 抵扣券 只选一个 并且无规格
    private void validateCommodityCoupon(List<Long> commodityIds, CouponType couponType, CouponScene couponScene) {
        if (couponScene == CouponScene.COMMODITY && couponType == CouponType.DEDUCTION) {
            if (CollUtil.isEmpty(commodityIds) || commodityIds.size() != 1) {
                throw new BadRequestException(ErrorCode.BUSINESS_ERROR, EscapeUtil.errorMessage("commoditiesIds", "当前情景下，卖品只允许选一个"));
            }
            
            Long commodityId = commodityIds.get(0);
            List<CommoditySkuEntity> commoditySkus = commoditySkuService.listByCommodityId(commodityId);
            if (CollUtil.isEmpty(commoditySkus) || commoditySkus.size() != 1) {
                throw new BadRequestException(ErrorCode.BUSINESS_ERROR, EscapeUtil.errorMessage("commoditiesIds", "当前情景下，卖品只允许选无规格"));
            }
        }
    }
    
    private void validateId(Long id) {
        if (service.isEmpty(id)) {
            throw new BadRequestException(
                ErrorCode.RECORD_NOT_EXIST,
                EscapeUtil.errorMessage("id", ErrorCode.RECORD_NOT_EXIST.getReasonPhrase())
            );
        }
    }
}
